﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;

namespace Nx.Services
{
    public class EndpointFactory : IEndpointFactory
    {
        public ServiceEndpoint CreateEndpoint<TContract>(Binding binding, string uri, string endpointName)
        {
            ContractDescription contractDescription = ContractDescription.GetContract(typeof(TContract));
            contractDescription.Name = endpointName;

            ServiceEndpoint endpoint = new ServiceEndpoint(contractDescription, binding, new EndpointAddress(uri));
            return endpoint;
        }

        public ServiceEndpoint CreateEndpoint<TContract>(Binding binding, string uri, string endpointName, string ns)
        {
            ContractDescription contractDescription = ContractDescription.GetContract(typeof(TContract));
            contractDescription.Name = endpointName;
            contractDescription.Namespace = ns;

            ServiceEndpoint endpoint = new ServiceEndpoint(contractDescription, binding, new EndpointAddress(uri));
            return endpoint;
        }

        public ServiceEndpoint CreateEndpoint<TContract>(Binding binding, EndpointAddress address, string endpointName)
        {
            ContractDescription contractDescription = ContractDescription.GetContract(typeof(TContract));
            contractDescription.Name = endpointName;

            ServiceEndpoint endpoint = new ServiceEndpoint(contractDescription, binding, address);
            return endpoint;
        }

        public ServiceEndpoint CreateEndpoint<TContract>(Binding binding, EndpointAddress address, string endpointName, string ns)
        {
            ContractDescription contractDescription = ContractDescription.GetContract(typeof(TContract));
            contractDescription.Name = endpointName;
            contractDescription.Namespace = ns;
            ServiceEndpoint endpoint = new ServiceEndpoint(contractDescription, binding, address);
            return endpoint;
        }

        public ServiceEndpoint CreateHttpBinaryEndpoint<TContract>(string uri, string endpointName)
        {
            ContractDescription contractDescription = ContractDescription.GetContract(typeof(TContract));
            contractDescription.Name = endpointName;
            ServiceEndpoint endpoint = new ServiceEndpoint(contractDescription, BindingFactory.Instance.CreateHttpBinaryBinding(), new EndpointAddress(uri));
            return SetEndpointName(endpoint, endpointName);
        }

        public ServiceEndpoint CreateNetNamedPipeEndpoint<TContract>(string uri, string endpointName)
        {
            ContractDescription contractDescription = ContractDescription.GetContract(typeof(TContract));
            contractDescription.Name = endpointName;
            ServiceEndpoint endpoint = new ServiceEndpoint(contractDescription, BindingFactory.Instance.CreateNetNamedPipeBinding(), new EndpointAddress(uri));
            return endpoint;
        }

        public ServiceEndpoint CreateMexEndpoint(string uri)
        {
            ContractDescription contract = ContractDescription.GetContract(typeof(IMetadataExchange));
            return new ServiceEndpoint(contract, MetadataExchangeBindings.CreateMexHttpBinding(), new EndpointAddress(uri));
        }

        public ServiceEndpoint CreateMexTcpEndpoint(string uri)
        {
            ContractDescription contract = ContractDescription.GetContract(typeof(IMetadataExchange));
            ServiceEndpoint endpoint = new ServiceEndpoint(contract, MetadataExchangeBindings.CreateMexTcpBinding(), new EndpointAddress(uri));

            return endpoint;
        }

        public EndpointFactory()
        {
        }

        private ServiceEndpoint SetEndpointName(ServiceEndpoint endpoint, string name)
        {
            endpoint.Name = name;

            return endpoint;
        }

        #region IDisposable Members
        ~EndpointFactory()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
            }
        }
        #endregion
    }
}
